home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************/
- /* */
- /* */
- /* ***** ***** */
- /* ***** ***** */
- /* ***** ***** */
- /* ***** ***** */
- /* *************** *************** */
- /* ***************** ***************** */
- /* *************** *************** */
- /* ***** ***** TheNet */
- /* ***** ***** Portable. Compatible. */
- /* ***** ***** Public Domain */
- /* ***** ***** NORD><LINK */
- /* */
- /* This software is public domain ONLY for non commercial use */
- /* */
- /* */
- /*****************************************************************************/
-
- /* Level 4, Transport
- /* Version 1.01 */
- /* Hans Georg Giese, DF2AU, Hinter dem Berge 5, 3300 Braunschweig */
- /* 01-MAY-88 */
- /* Modified G8KBB April 1991
- * added bank switching version
- * use of register keyword for code size
- * use all.h header file
- * added auditing of level 4 connections optionally on MANAGED
- * remove unnecessary '== 1' and similar code
- * add ip router link to l4rx()
- * add stats gathering
- * add parameter to splcpy to support MTU changes to show no splitting
- *
- * September 1993 - released as TheNet X-1J
- *
- * extend L4 rx ACL to bar user callsign as well as node callsign
- */
-
- #include "all.h"
- #include "tntyp.h" /* Definition der Typen */
- #ifdef BANKED
- #define EXTERN extern
- #else
- #define EXTERN
- #endif
- #include "tnl4v.h"
- #include "tnl4e.h" /* Externe Definitionen */
-
- #ifdef MANAGED
- extern char L4audit[];
- #endif
-
- /*---------------------------------------------------------------------------*/
- VOID initl4() /* Level 4 initialisieren */
- {
- register unsigned cnt; /* Sratch Zaehler */
-
- inithd(&l4rxfl); /* Liste fuer empfangene Frames */
-
- for (cnt = NUMCIR, cirpoi = cirtab; /* gesamte Circuit Tabelle */
- cnt != 0; /* bearbeiten */
- --cnt, ++cirpoi)
- {
- cirpoi->state3 = /* Eintrag ist leer */
- cirpoi->numrx = /* keine Frames empfangen */
- cirpoi->numtx = 0; /* keine Frames zu senden */
- cirpoi->fragme = NULL; /* kein Frame Fragment da */
- inithd(&cirpoi->mbhdrx); /* Empfangskette ist leer */
- inithd(&cirpoi->mbhdtx); /* Sendekette ist leer */
- inithd(&cirpoi->mbhdos); /* Kette "ausser Reihenfolge" leer */
- }
- if (! iswarm()) /* im Kaltstart Standardwerte */
- {
- tratou = DEFTTO; /* Timeout */
- tratri = DEFTTR; /* Versuche */
- traack = DEFTAC; /* ACK Wartezeit */
- trabsy = DEFTBS; /* Busy Wartezeit */
- trawir = DEFTWI; /* Fenstergroesse */
- }
- }
-
- /*---------------------------------------------------------------------------*/
- VOID l4serv() /* Level 4 Service */
- {
- l4tx(); /* Frames senden */
- l4rx(); /* Frames empfangen */
- l4rest(); /* sonstige Funktionen */
- }
-
- /*---------------------------------------------------------------------------*/
- VOID l4tx() /* Frames senden */
- {
- register unsigned unack; /* unbestaetigte Frames */
- register unsigned cnt; /* Sratch Zaehler */
- register mhtyp *nxtfra; /* naechstes Frame */
- unsigned isweg; /* schon gesendete Frames */
-
- for (cnt = 0, cirpoi = cirtab;/* gesamte Circuittabelle */
- cnt < NUMCIR;
- ++cnt, ++cirpoi) {
- if ((cirpoi->state3 == 2) /* Eintrag ist connected */
- && (!(cirpoi->l4flag & 0x20)) /* und Partner nicht choked */
- && ((unack = (cirpoi->l4vs - cirpoi->l4rxvs) & 0xff) < cirpoi->numtx)
- && (unack < cirpoi->window)) { /* Fenstergroesse nicht erreicht */
- for (isweg = 0, nxtfra = (mhtyp *) cirpoi->mbhdtx.lnext; /* neue Frames*/
- isweg < unack; /* schon gesendete offene Frames uebergehen */
- ++isweg, nxtfra = (mhtyp *) nxtfra->link.lnext);
- do {
- nxtfra->l4trie = 0; /* Versuche := 0 */
- sndfrm(cirpoi->l4vs++, nxtfra); /* naechstes Frame senden */
- nxtfra = (mhtyp *) nxtfra->link.lnext; /* vorruecken */
- }
- while ((++unack < cirpoi->numtx) /* bis Ende der Kette */
- && (cirpoi->window > unack)); /* oder Fenstergroesse ueberschritten */
- }
- }
- }
-
- /*---------------------------------------------------------------------------*/
- VOID l4rx() /* Frames empfangen */
- {
- char usrcal[7]; /* Call des Users */
- char orgnod[7]; /* Call des absendenden Knotens */
- unsigned fenste; /* Fenstergroesse */
- register unsigned cnt; /* Scratch Zaehler */
- mhtyp *antwor; /* Antwort auf Frame */
- register cirtyp *cirent; /* CIRTAB Eintrag des Users */
- register mhtyp *nxtfra; /* naechstes Frame */
-
- while ((nxtfra = (mhtyp *) l4rxfl.lnext) != (mhtyp *) &l4rxfl.lnext) {
- #ifdef STATSCMD
- L4RXCNT[0]++; /* bump received L4 packet count */
- #endif
- unlink(nxtfra); /* Frame aus Kette loesen */
- if ((nxtfra->putcnt - nxtfra->getcnt) >= 5) { /* lang genug? */
- l4hdr0 = getchr(nxtfra); /* Header holen */
- l4hdr1 = getchr(nxtfra);
- l4hdr2 = getchr(nxtfra);
- l4hdr3 = getchr(nxtfra);
- if (((l4opco = getchr(nxtfra)) & 0x07) != 0x01) { /* CONREQ immer gut */
- if ((l4hdr0 < NUMCIR) /* Index im Bereich? */
- && ((cirpoi = &cirtab[l4hdr0])->state3 != 0)
- && (cirpoi->ideige == l4hdr1)) {
- l4pidx = cirpoi->idxpar;
- l4pcid = cirpoi->idpart;
- }
- #ifdef IPROUTE
- /* if the frame appears to be an IP frame encapsulated in
- * a netrom frame, then link it to the ip receive list
- */
- else if( l4opco == NR4_OP_PID &&
- l4hdr0 == NR_PROTO_IP &&
- l4hdr1 == NR_PROTO_IP )
- {
- nxtfra->pid = PID_IP;
- relink( nxtfra, iprxfl.lprev );
- continue;
- }
- #endif
- else { /* schlechter Header */
- dealmb(nxtfra); /* Frame vernichten */
- continue;
- }
- }
- switch (l4opco & 0x07) { /* ueber Opcode verzweigen */
- /*=============================*/
- case 1: /* Connect Request */
- if (((nxtfra->putcnt - nxtfra->getcnt) >= 15) /* Frame lang genug? */
- && ((fenste = getchr(nxtfra) & 0xff) != 0) /* Fenster muss sein */
- && (getfid(usrcal, nxtfra) /*== 1*/) /* gueltiges Usercall */
- && (getfid(orgnod, nxtfra) /*== 1*/) /* gueltiger Absender */
- && (iscall(orgnod) == TRUE)) /* Absender bekannt */
- {
- l4pidx = l4hdr0; /* Index und */
- l4pcid = l4hdr1; /* ID des Partners merken */
- for (cirent = 0, cnt = 0, cirpoi = cirtab; /* Circuit Tabelle absuchen */
- cnt < NUMCIR;
- ++cnt, ++cirpoi) {
- if (cirpoi->state3 != 0) {
- if ((cmpid(usrcal, cirpoi->upcall) /*== 1*/)
- && (cmpid(orgnod, cirpoi->downca) /*== 1*/)) {
- if ((cirpoi->idxpar == l4hdr0)
- && (cirpoi->idpart == l4hdr1)) break;
- }
- }
- else {
- if (cirent == 0) cirent = cirpoi;
- }
- }
- if (cnt == NUMCIR) { /* Ende der Tabelle erreicht? */
- if ((cirent != 0) /* freien Platz gefunden? */
- #ifdef ACL
- && !( (acl_mask & ACL_BAR_L4_IC ) &&
- ((acl_entry( usrcal ) & ACL_BAR_L4_IC ) ||
- (acl_entry( orgnod ) & ACL_BAR_L4_IC )))
- #endif
- && (fvalca(VCpar, usrcal) == 1)) { /* User Call gueltig? */
- cirpoi = cirent; /* dann Eintrag nehmen */
- cpyid(cirpoi->upcall, usrcal); /* Call eintragen */
- cpyid(cirpoi->downca, orgnod);
- cirpoi->idxpar = l4hdr0; /* Parameter des Partnerknotens */
- cirpoi->idpart = l4hdr1;
- cirpoi->ideige = random(); /* eigener ID */
- cirpoi->l3node = despoi; /* Nachbar fuer den Eintrag */
- l2tol7(1, cirpoi, 4); /* UA von Circuit nach zurueck */
- #ifdef MANAGED
- l4audit( AudCon ); /* audit the level 4 connect */
- #endif
- cirpoi->tranoa = ininat; /* Timeout setzen */
- }
- else { /* kein Platz - ungueltiges Call */
- l4ahd2 = /* Antwort aufbauen */
- l4ahd3 = 0;
- l4aopc = 0x82; /* Opcode = choked, Acknowledge */
- (antwor = gennhd())->l2lnk = (l2ltyp *) despoi; /* Antwort aufbauen */
- relink(antwor, l3txl.lprev); /* in Sendekette haengen */
- #ifdef STATSCMD
- L4TXCNT[0]++; /* bump transmitted level 4 frame count */
- #endif
- break;
- }
- } /* Eintrag gibt es schon */
- cirpoi->window = (fenste > trawir)? trawir : fenste;
- clrcir(); /* Eintrag initialisieren */
- l4ahd2 = (cirpoi - &cirtab[0]);
- l4ahd3 = cirpoi->ideige; /* eigene Parameter setzen */
- l4aopc = 0x02; /* Antwort wird ACK */
- putchr(cirpoi->window, (antwor = gennhd()));
- itol3(antwor); /* senden */
- cirpoi->state3 = 2; /* Status = connected */
- }
- break;
-
- /*=============================*/
- case 2: /* Connect Acknowledge */
- if (cirpoi->state3 == 1) { /* macht nur Sinn, wenn Connect verlangt */
- if ((l4opco & 0x80) == 0) { /* Partner darf nicht choked sein */
- if (nxtfra->getcnt < nxtfra->putcnt) { /* noch Info da? */
- cirpoi->window = getchr(nxtfra); /* holen */
- cirpoi->idpart = l4hdr3; /* Partner Parameter setzen */
- cirpoi->idxpar = l4hdr2;
- clrcir(); /* Eintrag initialisieren */
- l2tol7(1, cirpoi, 4); /* Antwort ist UA vom Circuit */
- cirpoi->tranoa = ininat; /* Timeout setzen */
- #ifdef MANAGED
- l4audit( AudConAcc ); /* audit connect acceptance */
- #endif
- cirpoi->state3 +=1; /* Status = connected */
- }
- }
- else { /* Partner ist choked */
- l4nsta(3); /* melden */
- }
- }
- break;
-
- /*=============================*/
- case 3: /* Disconnect Request */
- clr4rx(1); /* restliche Info senden */
- #ifdef MANAGED
- l4audit( AudDisc ); /* audit level 4 disconnect */
- #endif
- l4nsta(2); /* nach oben melden */
- l4ahd2 =
- l4ahd3 = 0; /* Antwort aufbauen */
- l4aopc = 0x04; /* Opcode = Disconnect ACK */
- itol3(gennhd()); /* Frame senden */
- break;
-
- /*=============================*/
- case 4: /* Disconnect Acknowledge */
- if (cirpoi->state3 == 3) { /* wurde DISC gegeben? */
- l4nsta(2); /* melden */
- }
- #ifdef MANAGED
- l4audit( AudDiscAcc ); /* audit level 4 disconnect acceptance */
- #endif
- break;
-
- /*=============================*/
- case 5: /* Info Transfer */
- if (cirpoi->state3 != 2) /* nur wenn connected */
- break;
- chksts(); /* Status Info auswerten */
- if (((nxtfra->pid = (l4hdr2 - cirpoi->l4vr) & 0xff) < cirpoi->window)
- && ((cirpoi->l4flag & 0x40) == 0)) { /* passt das Frame ins Fenster? */
- nxtfra->morflg = (l4opco & 0x20) != 0; /* fragmentiert? */
- if (nxtfra->pid == 0) { /* passt Sequenz? */
- takfrm(nxtfra); /* Frame uebernehmen */
- for (cnt = 1, antwor = (mhtyp *) cirpoi->mbhdos.lnext; /* Frames, */
- (mhtyp *) &(cirpoi->mbhdos) != antwor; /* die zu frueh kamen, absu- */
- antwor = (mhtyp *) antwor->link.lnext) { /* chen, ob nun passt */
- if ((antwor->pid -=cnt) == 0) { /* neuer Offset */
- nxtfra = (mhtyp *) antwor->link.lprev; /* Frame passt bei Offset 0 */
- takfrm(unlink(antwor)); /* Frame aus Kette nehmen und verwerten */
- antwor = nxtfra;
- ++cnt; /* zulaessiger Offset eins weiter */
- }
- }
- cirpoi->l4rs = 0; /* Antwort wird ACK */
- #ifdef MODIFIED
- set_acktim();
- #else
- cirpoi->acktim = traack; /* ACK Timer laden */
- #endif
- }
- else { /* Sequenz passt nicht */
- for (antwor = (mhtyp *) cirpoi->mbhdos.lnext;;)
- { /* in extra Kette haengen */
- if ((mhtyp *) &(cirpoi->mbhdos) == antwor) { /* Ende der Kette? */
- relink(nxtfra, cirpoi->mbhdos.lprev); /* dann einhaengen */
- break;
- }
- if (antwor->pid == nxtfra->pid) { /* Frame schon mal angekommen? */
- dealmb(nxtfra); /* dann wegwerfen */
- break;
- }
- if (antwor->pid > nxtfra->pid) { /* an passender Stelle einhaengen */
- relink(nxtfra, antwor->link.lprev);
- break;
- }
- antwor = (mhtyp *) antwor->link.lnext; /* ein Frame weiter */
- }
- if (cirpoi->l4rs == 0) { /* Frame haengt in extra Kette */
- cirpoi->l4rs = 1; /* wenn ACK gefordert war, nun NAK */
- #ifdef MODIFIED
- set_acktim();
- #else
- cirpoi->acktim = traack; /* ACK Wartezeit setzen */
- #endif
- }
- }
- continue; /* naechstes Frame */
- }
- else /* ungueltiges Frame oder selbst choked */
- #ifdef MODIFIED
- set_acktim();
- #else
- cirpoi->acktim = traack; /* Antwort hat Zeit */
- #endif
- break;
-
- /*=============================*/
- case 6: /* Info Acknowledge */
- if (cirpoi->state3 == 2) /* nur sinnvoll, wenn connected */
- chksts(); /* enthaltene Statusinfo auswerten */
- break;
-
- /*=============================*/
- default: /* ungueltiger Opcode */
- break; /* uebergehen */
-
- /*=============================*/
- } } /* Ende des Switch ueber Opcode */
- dealmb(nxtfra); /* fertig bearbeitet, wegwerfen */
- } }
-
- /*---------------------------------------------------------------------------*/
- VOID l4rest() /* diverse Level4 Funktionen */
- {
- register unsigned cnt; /* Scratch Zaehler */
-
- for (cnt = 0, cirpoi = cirtab; /* gesamte Tabelle bearbeiten */
- cnt < NUMCIR;
- ++cnt, ++cirpoi) {
- if (cirpoi->state3 == 2) { /* nur fuer connectete Eintrage */
- if (((cirpoi->l4flag & 0x80) != 0) /* Abwurf gefordert */
- && (cirpoi->numtx == 0)) { /* und alles gesendet? */
- endcir(); /* Eintrag loeschen */
- }
- else {
- clr4rx(0); /* kein Abwurf gefordert: Info senden */
- if ((cirpoi->l4flag & 0x40) == 0) { /* selbst choked? */
- if ((nmbfre < 80) /* nein: kein Platz im Buffer? */
- || (cirpoi->numrx >= conctl)) { /* oder zu viel empfangen? */
- cirpoi->l4flag |= 0x40; /* dann selbst choked setzen */
- cirpoi->l4rs = 0; /* ACK als naechste Antwort */
- sndack();
- }
- }
- else {
- if ((nmbfre > 112) /* selbst choked: wieder Platz im Buffer? */
- && (cirpoi->numrx < (conctl / 2))) { /* und Datenstau abgebaut? */
- cirpoi->l4flag &= 0xffbf; /* dann choked ruecksetzen */
- sndack(); /* melden */
- } }
- } }
- } }
-
- /*---------------------------------------------------------------------------*/
- VOID trasrv() /* Timerservice fuer Level 4 */
- {
- unsigned actsts; /* Status des aktuellen Eintrages */
- unsigned fropen; /* Zahl der unbestaetigten Frames */
- register unsigned cnt; /* Scratch Zaehler */
- register unsigned tosend; /* Zahl der zu sendenden Frames */
- register mhtyp *nxtfra; /* aktuelles Frame */
-
- for (cnt = 0, cirpoi = cirtab; /* gesamte Tabelle bearbeiten */
- cnt < NUMCIR;
- ++cnt, ++cirpoi) {
- if ((actsts = cirpoi->state3) != 0) { /* nur aktive Eintraege */
- if (cirpoi->traout != 0) { /* Timeout noch nicht abgelaufen */
- if (--cirpoi->traout == 0) { /* Timeout nun abgelaufen? */
- if (actsts == 2) /* Status = connected? */
- cirpoi->l4flag &= 0xffdf; /* nichts neues senden */
- else { /* anderer Status: */
- if (++cirpoi->l4try < tratri) /* noch mal versuchen? */
- (actsts == 1)? sconrq() : sdisrq(); /* ja */
- else l4nsta(4); /* Fehler melden */
- }
- } }
- else { /* Timeout ist schon 0 */
- if ((actsts == 2) /* connectet und Frames unbestaetigt? */
- && ((fropen = (cirpoi->l4vs - cirpoi->l4rxvs) & 0xff) != 0)) {
- for (tosend = 0, nxtfra = (mhtyp *) cirpoi->mbhdtx.lnext;
- tosend < fropen; /* Frames wiederholen */
- ++tosend, nxtfra = (mhtyp *) nxtfra->link.lnext) {
- if (--nxtfra->l4time == 0) { /* wenn Timeout abgelaufen */
- if (++nxtfra->l4trie < tratri) /* und noch Versuche frei */
- sndfrm(nxtfra->pid, nxtfra);
- else {
- l4nsta(4); /* sonst melden */
- break;
- }
- }
- }
- }
- }
- if (actsts == 2) { /* connectet? */
- if ((cirpoi->acktim != 0)
- && (--cirpoi->acktim == 0)) /* ACK-Timer gerade abgelaufen? */
- sndack(); /* dann ACK senden */
- if ((cirpoi->tranoa != 0)
- && (--cirpoi->tranoa == 0)) /* No-activity-Timeout abgelaufen? */
- endcir(); /* dann abwerfen */
- }
- } }
- }
-
- /*---------------------------------------------------------------------------*/
- VOID newcir() /* neuen Circuit aufbauen */
- {
- clrcir(); /* Eintrag in CIRTAB loeschen */
- cirpoi->ideige = random(); /* eigenen ID erzeugen */
- cirpoi->l4try = 0; /* Versuche = 0 */
- sconrq(); /* Connect Request senden */
- cirpoi->state3 = 1; /* neuer Status */
- }
-
- /*---------------------------------------------------------------------------*/
- VOID discir() /* Circuit aufloesen */
- {
- if ((cirpoi->state3 == 1) /* Status CON-REQ? */
- || (cirpoi->state3 == 3)) /* oder DIS-REQ? */
- l4nsta(0); /* nicht nach oben, nur intern melden */
-
- else { /* connectet: */
- kilfra(); /* alle Fragmente loeschen */
- dealml(&cirpoi->mbhdrx); /* empfangene Frames loesschen */
- cirpoi->numrx = 0;
- cirpoi->l4flag |= 0x80; /* Abwurf einleiten */
- }
- }
-
- /*---------------------------------------------------------------------------*/
- BOOLEAN itocir(cflg, mbhd) /* Info an Circuit senden */
- register mhtyp *mbhd; /* Message Header */
- unsigned cflg; /* Congestion Flag */
- {
- register cirtyp *cblk; /* Kontrollblock */
-
- if (((cblk = (cirtyp *) mbhd->l2lnk)->numtx < conctl) /* Platz? */
- || (cflg == 1)) /* immer senden? */
- {
- relink(unlink(mbhd), cblk->mbhdtx.lprev); /* Info umhaengen */
- ++cblk->numtx; /* Frames zaehlen */
- mbhd->morflg = 0; /* Frame komplett */
- cblk->tranoa = ininat; /* Timeout neu */
- return(TRUE); /* hat funktioniert */
- }
- else return(FALSE); /* Fehler, ging nicht*/
- }
-
- /*---------------------------------------------------------------------------*/
- VOID clr4rx(cflg) /* restliche Info senden */
- unsigned cflg; /* Congestion Flag */
- {
- register mhtyp *mbhd; /* Message Header */
-
- while (cirpoi->numrx != 0) { /* ein Frame nach dem anderen */
- (mbhd = (mhtyp * )cirpoi->mbhdrx.lnext)->l2lnk = (l2ltyp *)cirpoi;
- mbhd->usrtyp = 4; /* User ist Circuit */
- if (fmlink(cflg, mbhd) == 0) break; /* Ende bei Fehler */
- cirpoi->tranoa = ininat; /* Timeout setzen */
- --cirpoi->numrx; /* ein Frame ist weg */
- }
- }
-
- /*---------------------------------------------------------------------------*/
- VOID chksts() /* Status des eingelaufenen Frames auswerten */
- {
- register unsigned frofs; /* bestaetigter Offset */
- register unsigned fropen; /* unbestaetigte Frames */
-
- if ((
- fropen = (cirpoi->l4vs - cirpoi->l4rxvs) & 0xff
- ) != 0) { /* Frames offen? */
- if ((
- frofs = (l4hdr3 - cirpoi->l4rxvs) & 0xff /* neu bestaetigte Frames */
- ) != 0) {
- if (frofs <= fropen) {
- while (frofs-- != 0) {
- dealmb(unlink(cirpoi->mbhdtx.lnext)); /* koennen weg */
- --cirpoi->numtx; /* eins weniger zu senden */
- ++cirpoi->l4rxvs; /* eins mehr bestaetigt */
- } } } }
- if ((l4opco & 0x80) == 0) { /* Partner choked? */
- cirpoi->l4flag &= 0xffdf; /* nein: merken */
- cirpoi->traout = 0; /* Timeout kann nicht kommen */
- if (((l4opco & 0x40) != 0) /* NAK Flag? */
- && (cirpoi->l4vs != cirpoi->l4rxvs)) /* und noch was offen? */
- sndfrm(cirpoi->l4rxvs, cirpoi->mbhdtx.lnext); /* dann wiederholen */
- }
- else { /* Partner ist choked */
- cirpoi->l4flag |= 0x20; /* merken */
- cirpoi->traout = trabsy; /* warten */
- cirpoi->l4vs = cirpoi->l4rxvs; /* keine Frames offen */
- }
- }
-
- /*---------------------------------------------------------------------------*/
- VOID takfrm(mbhdp) /* empfangenes Frame uebernehmen */
- mhtyp *mbhdp;
- {
- register mhtyp *mbhd;
- register char *nxt1; /* naechstes Zeichen des ersten Teils */
- unsigned get1; /* Getcount des ersten Teils */
- unsigned more; /* Frame ist auch nur Fragment */
- register mhtyp *fragmn; /* Fragment des Frames */
-
- mbhd = mbhdp;
- if ((cirpoi->l4flag & 0x80) == 0) { /* liegt DISC-REQ vor? */
- if ((fragmn = cirpoi->fragme) == NULL) { /* noch kein Fragment vorhanden */
- if (mbhd->morflg == 1) { /* ist dies ein Fragment? */
- cirpoi->fragme = mbhd; /* dann nur merken */
- mbhd = NULL; /* Frame ist weg */
- } }
- else { /* Fragment schon vorhanden */
- nxt1 = fragmn->nxtchr; /* altes Ende merken */
- get1 = fragmn->getcnt;
- while (fragmn->getcnt < fragmn->putcnt)
- getchr(fragmn); /* auf Ende des ertsen Teils gehen */
- #ifdef MODIFIED
- mhtyp_copy( mbhd, fragmn );
- #else
- while (mbhd->getcnt < mbhd->putcnt)
- putchr(getchr(mbhd), fragmn); /* neues Frame anhaengen */
- #endif
- fragmn->nxtchr = nxt1; /* Pointer wieder auf alten Stand */
- fragmn->getcnt = get1;
- more = mbhd->morflg; /* kommt noch mehr? */
- dealmb(mbhd); /* neuer Teil kann weg */
- if (more == 0) { /* nichts mehr im Rohr? */
- mbhd = fragmn; /* dann ist das Ergebniss die neue Summe */
- cirpoi->fragme = 0; /* kein Fragment mehr da */
- }
- else mbhd = 0; /* es kommt noch was: Fragment bleibt */
- }
- if (mbhd != 0) { /* Frame noch da? */
- relink(mbhd, cirpoi->mbhdrx.lprev); /* dann in RX Liste haengen */
- ++cirpoi->numrx; /* ein Frame mehr da */
- }
- }
- else { /* Kanal soll abgeworfen werden */
- dealmb(mbhd); /* Frame vernichten */
- }
- ++cirpoi->l4vr; /* RX-Sequenz erhoehen */
- }
-
- /*---------------------------------------------------------------------------*/
- VOID sndfrm(txsequ, mbhd) /* Frame senden */
- register mhtyp *mbhd; /* Info */
- unsigned txsequ; /* Sendesequenz fuer L4 */
- {
- register char *next; /* Pointer auf letztes Zeichen des Headers */
- register mhtyp *netmhd; /* Netzwerk MBHD */
-
- l4ahd2 = /* VS in Netzwerkheader */
- mbhd->pid = txsequ; /* VS als PID */
- l4aopc = 5; /* Opcode = Info */
- ackhdr(); /* Rest des Headers erzeugen */
- next =
- (netmhd = gennhd()) /* Buffer fuer Netzwerkframe holen */
- ->nxtchr; /* Position Opcode merken (eins davor) */
- if ((
- #ifdef MODIFIED
- /* in modified form, allow big frames to be split
- */
- splcpy((256 - netmhd->putcnt), netmhd, mbhd, YES) /* Info umkopieren */
- #else
- splcpy((256 - netmhd->putcnt), netmhd, mbhd) /* Info umkopieren */
- #endif
- ) /*== 1*/) { /* hat alles reingepasst? */
- ++cirpoi->numtx; /* neun: ein Frame mehr */
- mbhd->morflg = TRUE; /* Fragmentierung markieren */
- }
- if (mbhd->morflg == TRUE)
- *(next -1) |= 0x20; /* MORE Flag im Opcode setzen */
- itol3(netmhd); /* Frame an Level3 liefern */
- mbhd->l4time = tratou; /* Timeout im Infoframe setzen */
- }
-
- /*---------------------------------------------------------------------------*/
- VOID l4nsta(frtyp) /* Statusaenderung in Level4 */
- char frtyp; /* als Reaktion auf : 0=intern, 1=UA, 2=DISC */
- { /* 3=DM, 4=L4-Versuche abgelaufen */
- clrcir(); /* alle Pointer im Eintrag loeschen */
- if (frtyp != 0) { /* nach oben melden? */
- l2tol7(frtyp, cirpoi, 4); /* meldender User ist der Circuit */
- }
- dealml(&cirpoi->mbhdrx); /* keine Frames empfangen */
- dealml(&cirpoi->mbhdtx); /* keine Frames zu senden */
- cirpoi->numrx = /* Emfangsliste ist leer */
- cirpoi->numtx = /* Sendeliste ist leer */
- cirpoi->state3 = 0; /* Status = Eintrag ist leer */
- }
-
- /*---------------------------------------------------------------------------*/
- VOID endcir() /* Circuit aufloesen */
- {
- clrcir(); /* Eintrag in CIRTAB loeschen */
- cirpoi->l4try = 0; /* Versuche ruecksetzen */
- sdisrq(); /* Abwurf einleiten */
- cirpoi->state3 = 3; /* neuer Status: DISC-REQ gegeben */
- }
-
- /*---------------------------------------------------------------------------*/
- VOID clrcir() /* Eintrag in CIRTAB loeschen */
- {
- kilfra(); /* Fragmente loeschen */
- dealml(&cirpoi->mbhdos); /* Messageliste dafuer auch */
- cirpoi->l4rxvs = /* alle Sequenzen auf 0 */
- cirpoi->l4vs =
- cirpoi->l4vr =
- cirpoi->l4rs = /* ACK-NAK Flag */
- cirpoi->traout = /* Timeout */
- cirpoi->l4flag = 0; /* niemand choked, kein DISC-REQ */
- }
-
- /*---------------------------------------------------------------------------*/
- VOID sconrq() /* CON-REQ senden */
- {
- register mhtyp *mbhd; /* Buffer fuer Frame */
-
- l4pidx = cirpoi - &cirtab[0]; /* Index setzen */
- l4pcid = cirpoi->ideige; /* Partner und eigener Index */
- l4ahd2 = /* zwei Bytes leer */
- l4ahd3 = 0;
- l4aopc = 1; /* Opcode */
- putchr (trawir, (mbhd = gennhd())); /* Rest des Headers */
- putfid(cirpoi->upcall, mbhd); /* beide Calls in das Frame */
- putfid(myid, mbhd);
- itol3(mbhd); /* an Level3 liefern */
- cirpoi->traout = tratou; /* Timeout setzen */
- }
-
- /*---------------------------------------------------------------------------*/
- VOID sdisrq() /* DISC-REQ senden */
- {
- l4pidx = cirpoi->idxpar; /* Index setzen */
- l4pcid = cirpoi->idpart; /* und ID */
- l4ahd2 = /* zwei Bytes leer */
- l4ahd3 = 0;
- l4aopc = 3; /* Opcode */
- itol3(gennhd()); /* Rest des Headers und dann an Level3 */
- cirpoi->traout = tratou; /* Timeout setzen */
- }
-
- /*---------------------------------------------------------------------------*/
- VOID sndack() /* ACK senden */
- {
- l4ahd2 = 0;
- l4aopc = 6; /* Opcode */
- ackhdr(); /* Rest des Headers */
- itol3(gennhd()); /* Rest des Headers und dann an Level3 */
- }
-
- /*---------------------------------------------------------------------------*/
- VOID ackhdr() /* ACK Header erzeugen */
- {
- l4pidx = cirpoi->idxpar; /* Partner Index */
- l4pcid = cirpoi->idpart; /* Partner ID */
- l4ahd3 = cirpoi->l4vr; /* RX-Sequenz */
- if ((cirpoi->l4flag & 0x40) != 0) /* selbst choked? */
- l4aopc |= 0x80; /* dann Flag setzen */
- else {
- if (cirpoi->l4rs == 1) { /* wird es ein NAK Header? */
- l4aopc |= 0x40; /* dann Flag setzen */
- cirpoi->l4rs = 2; /* NAK als gesendet markieren */
- }
- }
- cirpoi->acktim = 0; /* ACK Timer ruecksetzen */
- }
-
- /*---------------------------------------------------------------------------*/
- VOID itol3(mbhd) /* Info an Level3 */
- register mhtyp *mbhd;
- {
- mbhd->l2lnk = (l2ltyp *) cirpoi->l3node; /* Controllblock */
- relink(mbhd, l3txl.lprev); /* nur umhaengen */
- #ifdef STATSCMD
- L4TXCNT[0]++; /* bump tx count */
- #endif
- }
-
- /*---------------------------------------------------------------------------*/
- mhtyp *gennhd() /* Netzwerk Header erzeugen */
- {
- register unsigned cnt; /* Scratch Zaehler */
- register mhtyp *mbhd; /* Buffer fuer Info */
-
- mbhd = (mhtyp *) allocb(); /* Buffer besorgen */
- for (cnt = 15; cnt != 0; --cnt) /* die ersten 15 Bytes fuer den Header leer */
- putchr(0, mbhd);
- putchr(l4pidx, mbhd); /* Transport Header schreiben */
- putchr(l4pcid, mbhd);
- putchr(l4ahd2, mbhd);
- putchr(l4ahd3, mbhd);
- putchr(l4aopc, mbhd);
-
- return(mbhd); /* Buffer wird zurueck gegeben */
- }
-
- /*---------------------------------------------------------------------------*/
- VOID kilfra() /* Fragmente loeschen */
- {
- if (cirpoi->fragme != NULL) { /* schon leer? */
- dealmb(cirpoi->fragme); /* Fragment loeschen */
- cirpoi->fragme = NULL; /* Eintrag loeschen */
- }
- }
-
- /*- Ende Level 4 ------------------------------------------------------------*/
-
- /*--------------------------------------------------------------------------
- * This utility is used to audit level 4 connects and disconnects by
- * copying the info to all level 6 ccp users
- */
- #ifdef MANAGED
- l4audit( what )
- {
- if( auditmask & 8 )
- notify( L4audit, 6, cirpoi->downca, cirpoi->upcall, what, 2 );
- }
- #endif
-
- /* **********************************************************************
- * to save a bit of space and time, do this efficiently
- */
-
- #ifdef MODIFIED
- mhtyp_copy( from, to )
- register mhtyp *from, *to;
- {
- register unsigned i = from->putcnt - from->getcnt;
-
- while( i-- )
- putchr(getchr( from ), to );
- }
-
- #endif
-
-
- #ifdef MODIFIED
- set_acktim()
- {
- if( ( cirpoi->acktim = traack ) == 0 )
- sndack();
- }
-
- #endif